/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.pig4cloud.pig.ads.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dy.yunying.api.entity.AdRoleUser;
import com.dy.yunying.api.feign.RemoteAdRoleUserService;
import com.google.api.client.util.Lists;
import com.pig4cloud.pig.admin.api.vo.UserSelectVO;
import com.pig4cloud.pig.ads.dao.AdAccountDao;
import com.pig4cloud.pig.ads.pig.mapper.AdAccountAgentMapper;
import com.pig4cloud.pig.ads.pig.mapper.AdAccountMapper;
import com.pig4cloud.pig.ads.pig.mapper.AdAgentMapper;
import com.pig4cloud.pig.ads.service.AdAccountAgentService;
import com.pig4cloud.pig.ads.service.AdAccountService;
import com.pig4cloud.pig.ads.utils.DateUtils;
import com.pig4cloud.pig.api.dto.AdAccountAgentDto;
import com.pig4cloud.pig.api.dto.AdAccountResp;
import com.pig4cloud.pig.api.dto.AdAccountTreeResp;
import com.pig4cloud.pig.api.entity.AdAccount;
import com.pig4cloud.pig.api.entity.AdAccountAgent;
import com.pig4cloud.pig.api.entity.AdAgent;
import com.pig4cloud.pig.api.gdt.vo.GdtAdvFundsVO;
import com.pig4cloud.pig.api.util.JsonUtil;
import com.pig4cloud.pig.api.vo.AdAccountAgentVo;
import com.pig4cloud.pig.api.vo.AdAccountAgentVo.Advertiser;
import com.pig4cloud.pig.api.vo.AdAccountRequest;
import com.pig4cloud.pig.api.vo.AdAccountVo;
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.security.util.SecurityUtils;
import groovy.lang.Tuple2;
import groovy.lang.Tuple3;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 广告账户表
 *
 * @author pigx code generator
 * @date 2021-05-31 10:53:49
 */
@Service
@RequiredArgsConstructor
public class AdAccountServiceImpl extends ServiceImpl<AdAccountMapper, AdAccount> implements AdAccountService {

	private static final DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd").toFormatter();
	private static final ZoneOffset DONGBA_DISTRICT = ZoneOffset.ofHours(8);

	private final AdAccountAgentService adAccountAgentService;

	private final AdAccountMapper adAccountMapper;

	private final AdAgentMapper adAgentMapper;

	private final RemoteAdRoleUserService remoteAdRoleUserService;

	@Autowired
	private AdAccountDao adAccountDao;

	@Autowired
	private AdAccountAgentMapper adAccountAgentMapper;


	@Autowired
	private AdAccountMapper mapper;


	/**
	 * 分页列表
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R getPage(AdAccountRequest req) {
		// 获取当前用户拥有的角色
		List<Integer> roles = SecurityUtils.getRoles();
		List<String> throwUserList = new ArrayList<>();
		if (roles.contains(1) || (throwUserList = this.getThrowUserList(roles)).contains("0")) {
			req.setIsSys(1);
		}
		throwUserList.add(String.valueOf(Objects.requireNonNull(SecurityUtils.getUser()).getId()));

		if (StringUtils.isNotBlank(req.getThrowUser())) {
			req.setThrowUser("'" + req.getThrowUser().replace(",", "','") + "'");
		}
		if (req.getIsSys() != 1) {
			req.setUserIds("'" + StringUtils.join(throwUserList, "','") + "'");
		}
		List<AdAccountResp> records = adAccountMapper.selectDataByList(req);
		List<String> adAccountList = new ArrayList<>();
		if (ObjectUtils.isNotEmpty(records)) {
			records.forEach(dataAccount -> {
				String advertiserId = dataAccount.getAdvertiserId();
				if (StringUtils.isNotBlank(advertiserId)) {
					adAccountList.add(advertiserId);
				}
			});
		}
		//查头条的余额
		List<Map<String, Object>> resultTtBalance = adAccountMapper.selectTtAdAccountBalance(adAccountList);
		//List<Map<String, Object>> ttBalance =  resultTtBalance.stream().filter(item -> item.get("platformId").equals(Integer.parseInt(data.getMediaCode()))).collect(Collectors.toList());
		Map<Integer,List<Map<String, Object>>> mapBalance = resultTtBalance.stream().collect(Collectors.groupingBy(a1->(Integer) a1.get("platformId")));
		//可用总余额
		Map<String, Object> mapTtValidBalance = new HashMap<>();
		//现金可用余额
		Map<String, Object> mapTtValidCash = new HashMap<>();
		//赠款可用余额
		Map<String, Object> mapTtValidGrant = new HashMap<>();

		//查广点通的余额
		List<Map<String, Object>> resultGdtBalance = adAccountMapper.selectGdtAdAccountBalance(adAccountList);
		//现金
		Map<String, Object> mapGdtCASH = new HashMap<>();
		//赠送
		Map<String, Object> mapGdtGIFT = new HashMap<>();
		//分成
		Map<String, Object> mapGdtSHARED = new HashMap<>();

		if (ObjectUtils.isNotEmpty(resultGdtBalance)) {
			resultGdtBalance.forEach(data -> {
				if (data.get("funds") != null) {
					List<GdtAdvFundsVO> listJson = JsonUtil.fromJsonArray(String.valueOf(data.get("funds")), GdtAdvFundsVO.class);
					listJson.forEach(dataJson -> {
						if (dataJson.getFund_type().equals("FUND_TYPE_CASH")) {
							mapGdtCASH.put(String.valueOf(data.get("adAccount")), dataJson.getBalance());
						}
						if (dataJson.getFund_type().equals("FUND_TYPE_GIFT")) {
							mapGdtGIFT.put(String.valueOf(data.get("adAccount")), dataJson.getBalance());
						}
						if (dataJson.getFund_type().equals("FUND_TYPE_SHARED")) {
							mapGdtSHARED.put(String.valueOf(data.get("adAccount")), dataJson.getBalance());
						}
					});
				}
			});
		}

		//查广告账户的消耗
		AdAccountVo vo = new AdAccountVo();
		BeanUtils.copyProperties(req, vo);
		List<Map<String, Object>> resultCost = adAccountDao.selectCostAdAccount(vo);
		Map<String, Object> mapCost = new HashMap<>();
		resultCost.forEach(data -> {
			mapCost.put(String.valueOf(data.get("adAccount")), data.get("cost"));
		});

		// 封装返参
		records.forEach(data -> {
			if (ObjectUtils.isNotEmpty(resultCost)) {
				data.setCost(mapCost.get(data.getAdvertiserId()) == null ? BigDecimal.ZERO : (BigDecimal) mapCost.get(data.getAdvertiserId()));
			}
			Integer platformId = Integer.parseInt(data.getMediaCode());
			if (platformId.equals(1) || platformId.equals(9) || platformId.equals(10)) {
				List<Map<String, Object>> ttBalance = mapBalance.get(platformId);
				if (ObjectUtils.isNotEmpty(ttBalance)) {
					ttBalance.forEach(b -> {
						mapTtValidBalance.put(String.valueOf(b.get("adAccount")), b.get("balance"));
						mapTtValidCash.put(String.valueOf(b.get("adAccount")), b.get("valid_cash"));
						mapTtValidGrant.put(String.valueOf(b.get("adAccount")), b.get("valid_grant"));
					});
				}
				if (ObjectUtils.isNotEmpty(resultTtBalance)) {
					data.setValidBalance(mapTtValidBalance.get(data.getAdvertiserId()) == null ? BigDecimal.ZERO : (BigDecimal) mapTtValidBalance.get(data.getAdvertiserId()));
				}
				if (ObjectUtils.isNotEmpty(resultTtBalance)) {
					data.setValidCash(mapTtValidCash.get(data.getAdvertiserId()) == null ? BigDecimal.ZERO : (BigDecimal) mapTtValidCash.get(data.getAdvertiserId()));
				}
				if (ObjectUtils.isNotEmpty(resultTtBalance)) {
					data.setValidGrant(mapTtValidGrant.get(data.getAdvertiserId()) == null ? BigDecimal.ZERO : (BigDecimal) mapTtValidGrant.get(data.getAdvertiserId()));
				}
			}
			if (data.getMediaCode().equals("8")) {
				if (ObjectUtils.isNotEmpty(resultGdtBalance)) {
					BigDecimal GdtCASH = mapGdtCASH.get(data.getAdvertiserId()) == null ? BigDecimal.ZERO : (BigDecimal) mapGdtCASH.get(data.getAdvertiserId());
					BigDecimal GdtGIFT = mapGdtGIFT.get(data.getAdvertiserId()) == null ? BigDecimal.ZERO : (BigDecimal) mapGdtGIFT.get(data.getAdvertiserId());
					BigDecimal GdtSHARED = mapGdtSHARED.get(data.getAdvertiserId()) == null ? BigDecimal.ZERO : (BigDecimal) mapGdtSHARED.get(data.getAdvertiserId());
					data.setValidBalance((GdtCASH.add(GdtGIFT).add(GdtSHARED)).divide(new BigDecimal("100")).setScale(2,BigDecimal.ROUND_HALF_UP));
				}
			}
		});
		return R.ok(records);
	}

	/**
	 * 目标账户下拉框，显示相同管家账号下的其他普通广告账户
	 *
	 * @param housekeeper 管家账户   adAccount 广告账户
	 * @return
	 */
	@Override
	public R queryAccountByHousekeeper(String housekeeper, String adAccount) {
		List<Map<String, String>> resultTtBalance = adAccountMapper.queryAccountByHousekeeper(housekeeper, adAccount);
		return R.ok(resultTtBalance);
	}


	/**
	 * 查询列表
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R getList(AdAccountVo req) {
		QueryWrapper<AdAccount> wrapper = new QueryWrapper<>();
		wrapper.eq(StringUtils.isNotBlank(req.getMediaCode()), "media_code", req.getMediaCode());
		wrapper.eq(StringUtils.isNotBlank(req.getAdvertiserId()), "advertiser_id", req.getAdvertiserId());
		wrapper.like(StringUtils.isNotBlank(req.getAdvertiserName()), "advertiser_name", req.getAdvertiserName());
		wrapper.eq("throw_user", Objects.requireNonNull(SecurityUtils.getUser()).getId());
		wrapper.eq("is_delete", 0);
		wrapper.apply("advertiser_id != housekeeper");
		List<AdAccount> list = this.list(wrapper);
		return R.ok(list);
	}

	/**
	 * 查询列表-所有广告账户
	 *
	 * @param req
	 * @return
	 */
	@Override
	public List<AdAccount> getAllList(AdAccountVo req) {
		final LambdaQueryWrapper<AdAccount> queryWrapper = Wrappers.<AdAccount>lambdaQuery()
				.eq(StringUtils.isNotBlank(req.getMediaCode()), AdAccount::getMediaCode, req.getMediaCode())
				.eq(StringUtils.isNotBlank(req.getAdvertiserId()), AdAccount::getAdvertiserId, req.getAdvertiserId())
				.in(CollectionUtil.isNotEmpty(req.getAdvertiserIds()), AdAccount::getAdvertiserId, req.getAdvertiserIds())
				.like(StringUtils.isNotBlank(req.getAdvertiserName()), AdAccount::getAdvertiserName, req.getAdvertiserName())
				.eq(AdAccount::getIsDelete, 0);
		return this.list(queryWrapper);
	}

	/**
	 * 根据当前登录用户查询列表
	 *
	 * @param req
	 * @return
	 */
	@Override
	public List<AdAccount> getListByAccount(AdAccountVo req) {
		List<Integer> userIdArr = Lists.newArrayList();
		R result = remoteAdRoleUserService.getOwnerRoleUsers();

		if (null != result.getData()) {
			List<UserSelectVO> resultList = (List<UserSelectVO>) result.getData();
			//userIdArr = resultList.stream().map(userSelectVO -> userSelectVO.getUserId()).collect(Collectors.toList());
			for (int i = 0; i < resultList.size(); i++) {
				JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(resultList.get(i)));
				UserSelectVO userSelectVO = jsonObject.toJavaObject(UserSelectVO.class);
				userIdArr.add(userSelectVO.getUserId());
			}
		} else {
			userIdArr.add(SecurityUtils.getUser().getId());
		}

		QueryWrapper<AdAccount> wrapper = new QueryWrapper<>();
		if (StringUtils.isNotBlank(req.getMediaCode())) {
			wrapper.eq("media_code", req.getMediaCode());
		}
		if (StringUtils.isNotBlank(req.getAdvertiserId())) {
			wrapper.eq("advertiser_id", req.getAdvertiserId());
		}
		wrapper.in("throw_user", userIdArr);
		wrapper.eq("is_delete", 0);
		wrapper.apply("advertiser_id != housekeeper");
		List<AdAccount> list = this.list(wrapper);
		return list;
	}

	/**
	 * 编辑信息
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R edit(AdAccountVo req) {
		AdAccount account = new AdAccount();
		account.setId(Integer.parseInt(req.getId()));
		account.setThrowUser(req.getThrowUser());
		account.setIs_paccount(req.getIsPaccount());
		account.setUpdateUser(String.valueOf(SecurityUtils.getUser().getId()));
		account.setUpdateTime(new Date());
		boolean flag = this.updateById(account);
		if (flag) {
			return R.ok();
		}
		return R.failed();
	}

	/**
	 * 代理列表
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R getAccountAgentList(AdAccountAgentVo req) {
		QueryWrapper<AdAccountAgent> wrapper = new QueryWrapper<>();
		wrapper.eq("advertiser_id", req.getAdvertiserId());
		wrapper.eq("is_delete", 0);
		List<AdAccountAgent> accountAgentList = adAccountAgentService.list(wrapper);

		QueryWrapper<AdAgent> adAgentQueryWrapper = new QueryWrapper<>();
		adAgentQueryWrapper.eq("is_delete", 0);
		// 查询代理商
		List<AdAgent> adAgentList = adAgentMapper.selectList(adAgentQueryWrapper);
		for (AdAccountAgent adAccountAgent : accountAgentList) {
			for (AdAgent adAgent : adAgentList) {
				if (adAccountAgent.getAgentId().intValue() == adAgent.getId().intValue()) {
					adAccountAgent.setAgentName(adAgent.getAgentName());
					break;
				}
			}
		}

		return R.ok(accountAgentList);
	}

	/**
	 * 设置账户代理商
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R setupAccountAgent(AdAccountAgentVo req) {
		AdAccountAgent accountAgent = new AdAccountAgent();

		accountAgent.setAgentId(Integer.parseInt(req.getAgentId()));
		accountAgent.setAgentName(req.getAgentName());
		accountAgent.setEffectiveTime(DateUtils.stringToDate(req.getEffectiveTime(), DateUtils.YYYY_MM_DD_HH_MM_SS));
		accountAgent.setInvalidTime(DateUtils.stringToDate(req.getInvalidTime(), DateUtils.YYYY_MM_DD_HH_MM_SS));
		accountAgent.setUpdateUser(String.valueOf(SecurityUtils.getUser().getId()));
		accountAgent.setUpdateTime(new Date());

		QueryWrapper<AdAccountAgent> wrapper = new QueryWrapper<>();
		if (StringUtils.isNotBlank(req.getId())) {
			wrapper.notIn("id", req.getId());
		}
		wrapper.eq("advertiser_id", req.getAdvertiserId());
		wrapper.eq("is_delete", 0);
		wrapper.apply("date_format(invalid_time,'%Y-%m-%d') >= date_format('" + req.getEffectiveTime() + "','%Y-%m-%d')");
		wrapper.apply("date_format(effective_time,'%Y-%m-%d') <= date_format('" + req.getInvalidTime() + "','%Y-%m-%d')");
		int num = adAccountAgentService.count(wrapper);
		if (num > 0) {
			return R.failed("代理生效时间不能重叠");
		}

		// ID不为空做修改操作
		if (StringUtils.isNotBlank(req.getId())) {
			accountAgent.setId(Integer.parseInt(req.getId()));
			boolean flag = adAccountAgentService.updateById(accountAgent);
			if (flag) {
				return R.ok();
			}
		}

		accountAgent.setAdvertiserId(req.getAdvertiserId());
		accountAgent.setAdvertiserName(req.getAdvertiserName());
		accountAgent.setCreateUser(String.valueOf(SecurityUtils.getUser().getId()));
		accountAgent.setCreateTime(new Date());

		boolean flag = adAccountAgentService.save(accountAgent);
		if (flag) {
			return R.ok();
		}
		return R.failed();
	}

	/**
	 * 设置账户代理商
	 *
	 * @param req
	 */
	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class)
	@Override
	public void saveAccountAgent(AdAccountAgentVo req) {
		LocalDate effectiveDate = LocalDate.parse(req.getEffectiveTime(), DATE_FORMATTER);
		// 获取当前广告帐户下的代理生效和结束时间
		List<Tuple3<Integer, LocalDate, LocalDate>> agentsList = getAgentsList(req.getAdvertiserId(), req.getAdvertiserName(), effectiveDate);
		// 计算合适的代理结束时间
		Tuple3<LocalDate, Tuple2<Integer, LocalDate>, Tuple2<Integer, LocalDate>> localDateTuple = computeInvalidDate(effectiveDate, agentsList, null);

		AdAccountAgent accountAgent = new AdAccountAgent();
		accountAgent.setAdvertiserId(req.getAdvertiserId());
		accountAgent.setAdvertiserName(req.getAdvertiserName());
		accountAgent.setAgentId(Integer.parseInt(req.getAgentId()));
		accountAgent.setAgentName(req.getAgentName());
		accountAgent.setEffectiveTime(new Date(effectiveDate.atStartOfDay().toInstant(DONGBA_DISTRICT).toEpochMilli()));
		accountAgent.setInvalidTime(new Date(localDateTuple.getFirst().atStartOfDay().toInstant(DONGBA_DISTRICT).toEpochMilli()));
		accountAgent.setCreateUser(String.valueOf(Objects.requireNonNull(SecurityUtils.getUser()).getId()));
		accountAgent.setCreateTime(new Date());
		accountAgent.setUpdateUser(String.valueOf(Objects.requireNonNull(SecurityUtils.getUser()).getId()));
		accountAgent.setUpdateTime(new Date());

		updateInvalidTime(localDateTuple.getThird(), SecurityUtils.getUser().getId());

		adAccountAgentService.save(accountAgent);
	}

	/**
	 * 修改代理商
	 *
	 * @param req
	 */
	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class)
	@Override
	public void updateAccountAgent(AdAccountAgentVo req) {
		Integer id = Integer.valueOf(req.getId());
		AdAccountAgent one = adAccountAgentService.getOne(Wrappers.<AdAccountAgent>lambdaQuery().eq(AdAccountAgent::getId, id).eq(AdAccountAgent::getIsDelete, 0));
		if (null == one) {
			return;
		}

		AdAccountAgent accountAgent = new AdAccountAgent();
		accountAgent.setId(id);
		accountAgent.setAgentId(Integer.parseInt(req.getAgentId()));
		accountAgent.setAgentName(req.getAgentName());
		accountAgent.setUpdateUser(String.valueOf(Objects.requireNonNull(SecurityUtils.getUser()).getId()));
		accountAgent.setUpdateTime(new Date());

		LocalDate effectiveDate;
		LocalDate oldDate = LocalDateTime.ofInstant(one.getEffectiveTime().toInstant(), DONGBA_DISTRICT).toLocalDate();
		if (StringUtils.isNotEmpty(req.getEffectiveTime()) && (effectiveDate = LocalDate.parse(req.getEffectiveTime(), DATE_FORMATTER)).compareTo(oldDate) != 0) {
			// 获取当前广告帐户下的代理生效和结束时间
			List<Tuple3<Integer, LocalDate, LocalDate>> agentsList = getAgentsList(req.getAdvertiserId(), req.getAdvertiserName(), effectiveDate);
			// 计算合适的代理结束时间
			Tuple3<LocalDate, Tuple2<Integer, LocalDate>, Tuple2<Integer, LocalDate>> localDateTuple = computeInvalidDate(effectiveDate, agentsList, id);

			accountAgent.setEffectiveTime(new Date(effectiveDate.atStartOfDay().toInstant(DONGBA_DISTRICT).toEpochMilli()));
			accountAgent.setInvalidTime(new Date(localDateTuple.getFirst().atStartOfDay().toInstant(DONGBA_DISTRICT).toEpochMilli()));

			updateInvalidTime(localDateTuple.getSecond(), SecurityUtils.getUser().getId());
			updateInvalidTime(localDateTuple.getThird(), SecurityUtils.getUser().getId());
		}


		adAccountAgentService.updateById(accountAgent);
	}

	/**
	 * 批量添加代理商
	 *
	 * @param req
	 */
	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class)
	@Override
	public List<String> batchAddAccountAgent(AdAccountAgentVo req, Integer currentUserId) {
		List<String> failedList = new ArrayList<>();
		currentUserId = null == currentUserId ? Objects.requireNonNull(SecurityUtils.getUser()).getId() : currentUserId;

		String agentName = req.getAgentName();
		String agentId = req.getAgentId();
		LocalDate effectiveDate = LocalDate.parse(req.getEffectiveTime(), DATE_FORMATTER);
		for (Advertiser advertiser : req.getAdvertisers()) {
			Tuple3<LocalDate, Tuple2<Integer, LocalDate>, Tuple2<Integer, LocalDate>> localDateTuple;
			try {
				// 获取当前广告帐户下的代理生效和结束时间
				List<Tuple3<Integer, LocalDate, LocalDate>> agentsList = getAgentsList(advertiser.getAdvertiserId(), advertiser.getAdvertiserName(), effectiveDate);
				// 计算合适的代理结束时间
				localDateTuple = computeInvalidDate(effectiveDate, agentsList, null);
			} catch (Exception e) {
				failedList.add(String.format("%s(%s)", advertiser.getAdvertiserName(), advertiser.getAdvertiserId()));
				continue;
			}

			AdAccountAgent accountAgent = new AdAccountAgent();
			accountAgent.setAdvertiserId(advertiser.getAdvertiserId());
			accountAgent.setAdvertiserName(advertiser.getAdvertiserName());
			accountAgent.setAgentId(Integer.parseInt(agentId));
			accountAgent.setAgentName(agentName);
			accountAgent.setEffectiveTime(new Date(effectiveDate.atStartOfDay().toInstant(DONGBA_DISTRICT).toEpochMilli()));
			accountAgent.setInvalidTime(new Date(localDateTuple.getFirst().atStartOfDay().toInstant(DONGBA_DISTRICT).toEpochMilli()));
			accountAgent.setCreateUser(String.valueOf(currentUserId));
			accountAgent.setCreateTime(new Date());
			accountAgent.setUpdateUser(String.valueOf(currentUserId));
			accountAgent.setUpdateTime(new Date());

			updateInvalidTime(localDateTuple.getThird(), currentUserId);
			adAccountAgentService.save(accountAgent);
		}
		return failedList;
	}

	public List<Tuple3<Integer, LocalDate, LocalDate>> getAgentsList(String advertiserId, String advertiserName, LocalDate effectiveDate) {
		List<AdAccountAgent> agents = adAccountAgentMapper.selectList(Wrappers.<AdAccountAgent>lambdaQuery().select(AdAccountAgent::getId, AdAccountAgent::getAdvertiserId, AdAccountAgent::getEffectiveTime, AdAccountAgent::getInvalidTime)
				.eq(AdAccountAgent::getAdvertiserId, advertiserId).eq(AdAccountAgent::getIsDelete, 0).orderByAsc(AdAccountAgent::getEffectiveTime));
		List<Tuple3<Integer, LocalDate, LocalDate>> agentsList = new ArrayList<>();
		/*LocalDate prevEndDate = null;*/
		for (AdAccountAgent agent : agents) {
			LocalDate beginDate = LocalDateTime.ofInstant(agent.getEffectiveTime().toInstant(), DONGBA_DISTRICT).toLocalDate();
			LocalDate endDate = LocalDateTime.ofInstant(agent.getInvalidTime().toInstant(), DONGBA_DISTRICT).toLocalDate();
			// TODO: 校验已有数据是否发生重叠
			if (beginDate.compareTo(endDate) > 0) {
				throw new RuntimeException(String.format("广告帐户%s(%s)存在生效时间大于结束时间的数据，请检查数据", advertiserId, advertiserName));
			}
			/*if (null != prevEndDate && prevEndDate.compareTo(beginDate) >= 0) {
				throw new RuntimeException(String.format("广告帐户%s(%s)已有的生效或结束时间发生重叠，请检查数据", advertiserId, advertiserName));
			}
			prevEndDate = endDate;*/
			if (effectiveDate.compareTo(beginDate) == 0) {
				// 传入的生效时间与已有的生效时间重叠
				throw new RuntimeException(String.format("广告帐户%s(%s)中已存在'%s'生效时间", advertiserId, advertiserName, effectiveDate.format(DATE_FORMATTER)));
			}
			agentsList.add(new Tuple3<>(agent.getId(), beginDate, endDate));
		}
		return agentsList;
	}

	private Tuple3<LocalDate, Tuple2<Integer, LocalDate>, Tuple2<Integer, LocalDate>> computeInvalidDate(LocalDate effectiveDate, List<Tuple3<Integer, LocalDate, LocalDate>> agentsList, Integer existsId) {
		Tuple3<Integer, LocalDate, LocalDate> tempTuple = null, prevTuple = null, nextTuple = null;

		Tuple2<Integer, LocalDate> existsUpdateTuple = null;
		if (existsId != null) {
			// 首先将要修改的节点找出来
			Iterator<Tuple3<Integer, LocalDate, LocalDate>> its = agentsList.iterator();
			while (its.hasNext()) {
				Tuple3<Integer, LocalDate, LocalDate> tuple = its.next();
				if (tuple.getFirst().equals(existsId)) {
					prevTuple = tempTuple;
					nextTuple = its.hasNext() ? its.next() : null;
					its.remove();
					break;
				}
				tempTuple = tuple;
			}
			if (null != prevTuple && nextTuple != null) {
				// 要修改的节点作为中间节点
				existsUpdateTuple = new Tuple2<>(prevTuple.getFirst(), nextTuple.getSecond().minusDays(1));
			} else if (null != prevTuple) {
				// 要修改的节点作为尾结点
				existsUpdateTuple = new Tuple2<>(prevTuple.getFirst(), prevTuple.getSecond().plusYears(10));
			}
			tempTuple = null;
			nextTuple = null;
		}

		LocalDate invalidDate = null;
		Tuple2<Integer, LocalDate> noneUpdateTuple = null;
		if (effectiveDate != null) {
			// 查找新的前驱和后继节点
			for (Tuple3<Integer, LocalDate, LocalDate> tuple : agentsList) {
				if (effectiveDate.compareTo(tuple.getSecond()) < 0) {
					nextTuple = tuple;
					break;
				}
				tempTuple = tuple;
			}
			prevTuple = tempTuple;

			if (null == prevTuple && null == nextTuple) {
				// 当前广告账户未设置代理商
				invalidDate = effectiveDate.plusYears(10);
			} else if (null == prevTuple) {
				// 要插入的节点作为头结点
				invalidDate = nextTuple.getSecond().minusDays(1);
			} else if (null == nextTuple) {
				// 要插入的节点作为尾结点
				invalidDate = effectiveDate.plusYears(10);
				noneUpdateTuple = new Tuple2<>(prevTuple.getFirst(), effectiveDate.minusDays(1));
			} else {
				// 要插入的节点作为中间节点
				invalidDate = nextTuple.getSecond().minusDays(1);
				noneUpdateTuple = new Tuple2<>(prevTuple.getFirst(), effectiveDate.minusDays(1));
			}
		}

		return new Tuple3<>(invalidDate, existsUpdateTuple, noneUpdateTuple);
	}

	private void updateInvalidTime(Tuple2<Integer, LocalDate> localDateTuple, Integer currentUserId) {
		if (localDateTuple != null) {
			AdAccountAgent adAccountAgent = new AdAccountAgent();
			adAccountAgent.setId(localDateTuple.getFirst());
			adAccountAgent.setInvalidTime(new Date(localDateTuple.getSecond().atStartOfDay().toInstant(DONGBA_DISTRICT).toEpochMilli()));
			adAccountAgent.setUpdateUser(String.valueOf(currentUserId));
			adAccountAgent.setUpdateTime(new Date());
			adAccountAgentService.updateById(adAccountAgent);
		}
	}

	/**
	 * 批量设置代理商
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R setBatchAccountAgent(AdAccountAgentDto req) {

		//广告账户集合
		String[] advertiserArr = req.getAdvertiserArr();
		List<String> advertiserArrr = new ArrayList<>(Arrays.asList(advertiserArr));

		//代理生效时间重叠的广告账户集合
		List<AdAccountAgentDto> successList = new ArrayList<>();

		//代理生效时间重叠的广告账户集合
		List<String> errorList = new ArrayList<>();

		advertiserArrr.forEach(advertiserId -> {
			QueryWrapper<AdAccountAgent> wrapper = new QueryWrapper<>();
			if (StringUtils.isNotBlank(req.getId())) {
				wrapper.notIn("id", req.getId());
			}
			wrapper.eq("advertiser_id", advertiserId);
			wrapper.eq("is_delete", 0);
			wrapper.apply("date_format(invalid_time,'%Y-%m-%d') >= date_format('" + req.getEffectiveTime() + "','%Y-%m-%d')");
			wrapper.apply("date_format(effective_time,'%Y-%m-%d') <= date_format('" + req.getInvalidTime() + "','%Y-%m-%d')");
			int num = adAccountAgentService.count(wrapper);
			if (num > 0) {
				// 代理生效时间重叠的广告账户
				errorList.add(advertiserId);
			} else {
				//查询对应广告账户名称
				AdAccount adAccountAgent = this.getOne(Wrappers.<AdAccount>query()
						.lambda().eq(AdAccount::getAdvertiserId, advertiserId));

				// 代理生效时间不重叠的广告账户
				AdAccountAgentDto adAccountAgentDto = new AdAccountAgentDto();

				adAccountAgentDto.setAdvertiserId(advertiserId);
				adAccountAgentDto.setAdvertiserName(adAccountAgent.getAdvertiserName());
				adAccountAgentDto.setAgentId(req.getAgentId());
				adAccountAgentDto.setEffectTime(DateUtils.stringToDate(req.getEffectiveTime(), DateUtils.YYYY_MM_DD_HH_MM_SS));
				adAccountAgentDto.setDealTime(DateUtils.stringToDate(req.getInvalidTime(), DateUtils.YYYY_MM_DD_HH_MM_SS));
				adAccountAgentDto.setUpdateUser(String.valueOf(SecurityUtils.getUser().getId()));
				adAccountAgentDto.setUpdateTime(new Date());
				adAccountAgentDto.setCreateUser(String.valueOf(SecurityUtils.getUser().getId()));
				adAccountAgentDto.setCreateTime(new Date());

				successList.add(adAccountAgentDto);
			}
		});
		if (CollectionUtils.isNotEmpty(successList)) {
			// 批量插入成功的
			int count = adAccountAgentMapper.saveBatchAgent(successList);
			if (errorList.size() > 0) {
				//有失败有成功的
				return R.ok("插入成功" + count + "条" + "----" + "插入失败" + errorList.size() + "条-代理生效时间重叠" + errorList);
			} else {
				//只有成功的
				return R.ok("插入成功" + count + "条");
			}
		} else {
			return R.failed("插入失败" + errorList.size() + "条-代理生效时间重叠");
		}
	}

	/**
	 * 确定管家账户下 母账号唯一
	 *
	 * @param req
	 * @return
	 */
	@Override
	public AdAccount queryAdByHousekeeper(AdAccountVo req) {
		return adAccountMapper.queryAdByHousekeeper(req);
	}

	/**
	 * 删除账户代理商
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R delAccountAgent(AdAccountAgentVo req) {
		Integer id = Integer.valueOf(req.getId());
		AdAccountAgent one = adAccountAgentService.getOne(Wrappers.<AdAccountAgent>lambdaQuery().select(AdAccountAgent::getAdvertiserId, AdAccountAgent::getAdvertiserName).eq(AdAccountAgent::getId, id).eq(AdAccountAgent::getIsDelete, 0));
		if (null == one) {
			return R.ok();
		}

		// 获取当前广告帐户下的代理生效和结束时间
		List<Tuple3<Integer, LocalDate, LocalDate>> agentsList = getAgentsList(one.getAdvertiserId(), one.getAdvertiserName(), LocalDate.ofEpochDay(0));
		// 计算合适的代理结束时间
		Tuple3<LocalDate, Tuple2<Integer, LocalDate>, Tuple2<Integer, LocalDate>> localDateTuple = computeInvalidDate(null, agentsList, id);

		AdAccountAgent accountAgent = new AdAccountAgent();
		accountAgent.setId(id);
		accountAgent.setIsDelete(1);
		accountAgent.setUpdateUser(String.valueOf(SecurityUtils.getUser().getId()));
		accountAgent.setUpdateTime(new Date());
		boolean flag = adAccountAgentService.updateById(accountAgent);

		this.updateInvalidTime(localDateTuple.getSecond(), SecurityUtils.getUser().getId());

		if (flag) {
			return R.ok();
		}
		return R.failed();
	}

	/**
	 * 广告账户树形
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R getTree(AdAccountVo req) {
		List<AdAccountTreeResp> result = Lists.newArrayList();

		String mediaCode = req.getMediaCode();
		QueryWrapper<AdAccount> wrapper = new QueryWrapper<>();
		if (StringUtils.isNotBlank(mediaCode)) {
			wrapper.in("media_code", Arrays.asList(mediaCode.split(",")));
		}
		wrapper.eq("is_delete", 0);
		List<AdAccount> adAccountList = adAccountMapper.selectList(wrapper);
		adAccountList.forEach(adAccount -> {
			if (adAccount.getAdvertiserId().equals(adAccount.getHousekeeper())) {
				AdAccountTreeResp adAccountTreeResp = new AdAccountTreeResp();
				adAccountTreeResp.setAdvertiserId(adAccount.getAdvertiserId());
				adAccountTreeResp.setAdvertiserName(adAccount.getAdvertiserName());
				adAccountTreeResp.setMediaCode(adAccount.getMediaCode());
				adAccountTreeResp.setChildren(getChildren(adAccountList, adAccount.getAdvertiserId(), req.getUserArr(), req.getIsAdmin()));
				result.add(adAccountTreeResp);
			}
		});
		if (result.size() > 0) {
			for (int i = 0; i < result.size(); i++) {
				if (result.get(i).getChildren().size() == 0) {
					result.remove(i);
				}
			}
		}
		return R.ok(result);
	}

	public List<AdAccountTreeResp> getChildren(List<AdAccount> adAccountList, String advertiserId, List<String> userIdList, Boolean isAdmin) {
		List<String> userArr = Lists.newArrayList();
		if (CollectionUtils.isNotEmpty(userIdList)) {
			userArr = userIdList;
		} else {
			userArr.add(SecurityUtils.getUser().getId().toString());
		}
		List<String> userQueryArr = userArr;
		List<AdAccountTreeResp> result = Lists.newArrayList();
		adAccountList.forEach(adAccount -> {
			if (adAccount.getHousekeeper().equals(advertiserId)
					&& !adAccount.getAdvertiserId().equals(advertiserId)) {
				if (isAdmin) {
					AdAccountTreeResp adAccountTreeResp = new AdAccountTreeResp();
					adAccountTreeResp.setAdvertiserId(adAccount.getAdvertiserId());
					adAccountTreeResp.setAdvertiserName(adAccount.getAdvertiserName());
					adAccountTreeResp.setMediaCode(adAccount.getMediaCode());
					result.add(adAccountTreeResp);
				} else {
					if (userQueryArr.contains(adAccount.getThrowUser())) {
						AdAccountTreeResp adAccountTreeResp = new AdAccountTreeResp();
						adAccountTreeResp.setAdvertiserId(adAccount.getAdvertiserId());
						adAccountTreeResp.setAdvertiserName(adAccount.getAdvertiserName());
						adAccountTreeResp.setMediaCode(adAccount.getMediaCode());
						result.add(adAccountTreeResp);
					}
				}

			}
		});
		return result;
	}


	/**
	 * 查询用户列表绑定的广告账号列表
	 *
	 * @return
	 */
	@Override
	public R<List<AdAccount>> getAccountList(List<Integer> userIdArr) {
		if (CollectionUtils.isNotEmpty(userIdArr)) {
			return R.ok(baseMapper.selectList(Wrappers.<AdAccount>query().lambda().in(AdAccount::getThrowUser, userIdArr)));
		} else {
			return R.ok();
		}
	}

	@Override
	public List<String> getAccountList2(List<Integer> userIdArr) {
		List<String> adAccountList = new ArrayList<>();
		if (CollectionUtils.isNotEmpty(userIdArr)) {
			List<AdAccount> adAccounts = baseMapper.selectList(Wrappers.<AdAccount>query().lambda().in(AdAccount::getThrowUser, userIdArr));
			if (CollectionUtils.isNotEmpty(adAccounts)) {
				for (AdAccount adAccount : adAccounts) {
					adAccountList.add(adAccount.getAdvertiserId());
				}
			}
		}
		return adAccountList;
	}

	/**
	 * 根据授权查看广告账户列表
	 *
	 * @param req
	 * @return
	 */
	@Transactional(readOnly = true, rollbackFor = Exception.class)
	@Override
	public List<AdAccount> getAccountsByAuthorize(AdAccountVo req) {
		LambdaQueryWrapper<AdAccount> queryWrapper = Wrappers.lambdaQuery();
		queryWrapper.eq(StringUtils.isNotEmpty(req.getMediaCode()), AdAccount::getMediaCode, req.getMediaCode());
		queryWrapper.eq(StringUtils.isNotEmpty(req.getAdvertiserId()), AdAccount::getAdvertiserId, req.getAdvertiserId());
		queryWrapper.like(StringUtils.isNotEmpty(req.getAdvertiserName()), AdAccount::getAdvertiserName, req.getAdvertiserName());
		queryWrapper.apply("advertiser_id <> housekeeper");
		List<Integer> roles = SecurityUtils.getRoles();

		// 如果包含管理员角色，则直接返回所有广告账户
		if (roles.contains(1)) {
			return this.list(queryWrapper);
		}

		List<String> throwUserList = this.getThrowUserList(roles);
		// 如果查看授权中包含全账号，则直接返回所有广告账户
		if (throwUserList.contains("0")) {
			return this.list(queryWrapper);
		}

		throwUserList.add(String.valueOf(Objects.requireNonNull(SecurityUtils.getUser()).getId()));
		return this.list(queryWrapper.in(AdAccount::getThrowUser, throwUserList));
	}

	private List<String> getThrowUserList(List<Integer> roles) {
		R<List<AdRoleUser>> adRoleUserList = remoteAdRoleUserService.getUserListByRole(SecurityConstants.FROM_IN, roles);
		if (adRoleUserList == null || CollectionUtil.isEmpty(adRoleUserList.getData())) {
			return new ArrayList<>();
		}
		return adRoleUserList.getData().stream().distinct().map(AdRoleUser::getUserId).map(String::valueOf).collect(Collectors.toList());
	}

	@Override
	public void saveUpdateList(List<AdAccount> list) {
		if(CollectionUtils.isNotEmpty(list)) {
			this.saveOrUpdateBatch(list, 1000);
		}
	}


}
